#include "stdafx.h"
#include <boost/test/auto_unit_test.hpp>
#include <iostream>
#include <boost/test/execution_monitor.hpp>
#include "bmock.hpp"
#include "bmock_control_tools_mock.hpp"

static void f(int x)
{
	STATIC_MOCK_VOID(1, (IN(x)));
}

static void g(int y)
{
	STATIC_MOCK_VOID(1, (IN(y)));
}

static void g_c(int x, char y)
{
	STATIC_MOCK_VOID(2, (IN(x), IN(y)));
}

static void g_u_c(int x, unsigned char y)
{
	STATIC_MOCK_VOID(2, (IN(x), IN(y)));
}

static int k()
{
	STATIC_MOCK(0, ());
}

static void ig(int x, int y)
{
	STATIC_MOCK_VOID(2, (IGN(x), IN(y)));
}

static void ig2(int* x)
{
	STATIC_MOCK_VOID(1, (IGN(x)));
}

typedef void (* f_ptr)(int);
typedef int (*n_ptr)();

static void f_ptr1(n_ptr* x)
{
	STATIC_MOCK_VOID(1, (OUT(x)));
}

static void fg(n_ptr a)
{
	STATIC_MOCK_VOID(1, (CLBK(a)));
}

static void fg1(n_ptr b)
{
	STATIC_MOCK_VOID(1, (IN(b)));
}

static void fg2(void* b)
{
	STATIC_MOCK_VOID(1, (IN(b)));
}

static void h(f_ptr f)
{
	STATIC_MOCK_VOID(1, (IN_PTR(f)));
}

static void l(n_ptr f)
{
	STATIC_MOCK_VOID(1,(IN_PTR(f)));
}

static int Num[2]={1,1};
static const int           actual       = 10;
static const int           expected     = 11;
static const std::string   s_actual     = boost::lexical_cast<std::string>(actual);
static const std::string   s_expected   = boost::lexical_cast<std::string>(expected);
static const char          s_name[]     = "x";
static  void				(*p)(int)		=f;
static int					(*m)()	=k;
static int	(*n)();
static void*				ip=Num;
static void*				jp=NULL;

struct test_struct {
	test_struct(int y=0):x(y){}
	int x;
};

namespace std {
	ostream &operator <<(ostream &os,const test_struct &s) {
		os << s.x;
		return os;
	}
	istream &operator >>(istream &is,test_struct &s) {
		is >> s.x;
		return is;
	}
}

BOOST_AUTO_TEST_CASE(testArgumentsValidation_Ok) {
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,f(expected));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(f(expected));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidation_Multiple) {
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,f(expected));
	__BMOCK_EXPECT_C(c,f(actual));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(f(expected));
	BOOST_CHECK_NO_THROW(f(actual));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidation_InvalidParameter) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));	
	const bmock::location          loc(__FILE__,__LINE__+7);

	__BMOCK_EXPECT_RETURN_C(c,true,t->check_equal(s_expected,s_actual,bmock::message(bmock::ARG_VALUE,s_name),loc));
	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->abort(loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f(expected));
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_THROW(f(actual),bmock::location);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidation_InvalidFunctionName) {
	__BMOCK_CONTROL(c);
	const          bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const std::string msg = "BMOCK_EXPECT_STR(g,\"test_arguments_validation.cpp\",15,1,(IN(\"10\")));";
	const bmock::location loc(__FILE__,__LINE__+6);

	__BMOCK_EXPECT_THROW_C(c,new boost::execution_aborted(),t->error(msg,loc,true));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f(expected));
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_THROW(g(actual),boost::execution_aborted);
	}
	__BMOCK_VERIFY_C(c);
}
BOOST_AUTO_TEST_CASE(testArgumentsValidation_PtrToFunctionArgument) {
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,h(p));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(h(f));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidation_PtrToNotVoidFunctionArgument) {
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,l(k));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(l(k));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidationNotVoidFunctionArgumentwithCLBKmacro) {
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,fg(m));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(fg(m));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidationNotVoidFunctionArgumentwithINmacro) {
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,fg1(m));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(fg1(m));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidationVoidPointer) {
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,fg2(ip));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(fg2(Num));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidationVoidPointerNULL) {
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,fg2(jp));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(fg2(NULL));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidationIGNMacrodifferentValue) {
	int x=12;
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,ig(actual,x));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(ig(x,x));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidationIGNMacroSameValue) {
	int x=10;
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,ig(actual,x));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(ig(x,x));
	__BMOCK_VERIFY_C(c);

}

BOOST_AUTO_TEST_CASE(testArgumentsValidationIGN_NullPtr_NullExpect) {
	int x = 10;
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,ig2(NULL));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(ig2(&x));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidationIGN_NullPtr_NullAfterReplay) {
	int* px = new int(10);
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,ig2(px));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(ig2(NULL));
	__BMOCK_VERIFY_C(c);
	delete px;
}

BOOST_AUTO_TEST_CASE(testArgumentsValidationWithCharArgument) {
	unsigned char x_actual=0xE9;
	unsigned char y_actual=0xE9;

	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,g_c(9,(char)x_actual));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(g_c(9,(char)y_actual));
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testArgumentsValidationWithUnsignedCharArgument) {
	unsigned char x_actual=0xE9;
	unsigned char y_actual=0xE9;


	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,g_u_c(9,x_actual));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(g_u_c(9,y_actual));
	__BMOCK_VERIFY_C(c);
}


BOOST_AUTO_TEST_CASE(testArgumentsValidationNotVoidFunctionArgumentwithOUTmacro) {
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,f_ptr1(&m));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(f_ptr1(&n));
	__BMOCK_VERIFY_C(c);
	BOOST_CHECK_EQUAL(n,m);
}

